home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 24
/
Amiga Format AFCD24 (Feb 1998, Issue 108).iso
/
-in_the_mag-
/
emulation
/
amiga
/
uae-0.7.0b2
/
src
/
audio.c
next >
Wrap
C/C++ Source or Header
|
1998-01-20
|
8KB
|
378 lines
/*
* UAE - The Un*x Amiga Emulator
*
* OS specific functions
*
* Copyright 1995, 1996, 1997 Bernd Schmidt
* Copyright 1996 Marcus Sundberg
* Copyright 1996 Manfred Thole
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "options.h"
#include "memory.h"
#include "custom.h"
#include "gensound.h"
#include "sounddep/sound.h"
#include "events.h"
#include "audio.h"
int sound_available = 0;
struct audio_channel_data audio_channel[4];
int sound_table[256][64];
unsigned long int sample_evtime;
void init_sound_table16(void)
{
int i,j;
for (i = 0; i < 256; i++)
for (j = 0; j < 64; j++)
sound_table[i][j] = j * (uae_s8)i * (currprefs.stereo ? 2 : 1);
}
void init_sound_table8 (void)
{
int i,j;
for (i = 0; i < 256; i++)
for (j = 0; j < 64; j++)
sound_table[i][j] = (j * (uae_s8)i * (currprefs.stereo ? 2 : 1)) / 256;
}
void AUDxDAT(int nr, uae_u16 v)
{
#ifndef DONT_WANT_SOUND
struct audio_channel_data *cdp = audio_channel + nr;
cdp->dat = v;
if (cdp->state == 0 && !(INTREQR() & (0x80 << nr))) {
cdp->state = 2;
INTREQ(0x8000 | (0x80 << nr));
/* data_written = 2 ???? */
eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
eventtab[ev_aud0 + nr].oldcycles = cycles;
eventtab[ev_aud0 + nr].active = 1;
events_schedule();
}
#endif
}
#ifdef MULTIPLICATION_PROFITABLE
#define DO_CHANNEL_1(c) do { thisdata = (uae_s8)audio_channel[c].current_sample * audio_channel[c].vol; } while (0)
#define FINISH_DATA(b,logn) do { if (14 - (b) + (logn) > 0) data >>= 14 - (b) + (logn); else data <<= (b) - 14 - (logn); } while (0);
#else
#define DO_CHANNEL_1(c) do { thisdata = sound_table[audio_channel[c].current_sample][audio_channel[c].vol]; } while (0)
#define FINISH_DATA(b,logn)
#endif
#ifdef BRANCHES_ARE_EXPENSIVE
#define INIT_ADK(adk) ((adk) | ((adk) >> 4))
#define DO_CHANNEL(c) do { uae_u32 thisdata; DO_CHANNEL_1(c); data += thisdata & (((adk >> c) & 1) - 1); } while (0);
#else
#define INIT_ADK(adk) (adk)
#define DO_CHANNEL(c) do { uae_u32 thisdata; if (! (adk & (0x11 << c))) { DO_CHANNEL_1(c); data += thisdata; } } while (0);
#endif
/* Templates! I want templates! */
void sample16_handler(void)
{
#ifndef DONT_WANT_SOUND
int adk;
uae_u32 data = SOUND16_BASE_VAL;
eventtab[ev_sample].evtime = cycles + sample_evtime;
eventtab[ev_sample].oldcycles = cycles;
adk = INIT_ADK (adkcon);
DO_CHANNEL (0);
DO_CHANNEL (1);
DO_CHANNEL (2);
DO_CHANNEL (3);
FINISH_DATA(16, 2);
PUT_SOUND_WORD (data);
check_sound_buffers ();
#endif
}
void sample8_handler(void)
{
#ifndef DONT_WANT_SOUND
int adk;
uae_u32 data = SOUND8_BASE_VAL;
eventtab[ev_sample].evtime = cycles + sample_evtime;
eventtab[ev_sample].oldcycles = cycles;
adk = INIT_ADK (adkcon);
DO_CHANNEL (0);
DO_CHANNEL (1);
DO_CHANNEL (2);
DO_CHANNEL (3);
FINISH_DATA(8, 2);
PUT_SOUND_BYTE (data);
check_sound_buffers ();
#endif
}
#ifdef HAVE_STEREO_SUPPORT
void sample16s_handler(void)
{
#ifndef DONT_WANT_SOUND
int adk;
uae_u32 data = SOUND16_BASE_VAL;
eventtab[ev_sample].evtime = cycles + sample_evtime;
eventtab[ev_sample].oldcycles = cycles;
adk = INIT_ADK (adkcon);
DO_CHANNEL (0);
DO_CHANNEL (3);
FINISH_DATA (16, 1);
PUT_SOUND_WORD_RIGHT (data);
data = SOUND16_BASE_VAL;
DO_CHANNEL (1);
DO_CHANNEL (2);
FINISH_DATA (16, 1);
PUT_SOUND_WORD_LEFT (data);
check_sound_buffers ();
#endif
}
void sample8s_handler(void)
{
#ifndef DONT_WANT_SOUND
int adk;
uae_u32 data = SOUND8_BASE_VAL;
eventtab[ev_sample].evtime = cycles + sample_evtime;
eventtab[ev_sample].oldcycles = cycles;
adk = INIT_ADK (adkcon);
DO_CHANNEL (0);
DO_CHANNEL (3);
FINISH_DATA (8, 1);
PUT_SOUND_BYTE_RIGHT (data);
data = SOUND8_BASE_VAL;
DO_CHANNEL (1);
DO_CHANNEL (2);
FINISH_DATA (8, 1);
PUT_SOUND_BYTE_LEFT (data);
check_sound_buffers ();
#endif
}
#else
void sample8s_handler(void)
{
sample8_handler();
}
void sample16s_handler(void)
{
sample16_handler();
}
#endif
static uae_u8 int2ulaw(int ch)
{
int mask;
if (ch < 0) {
ch = -ch;
mask = 0x7f;
}
else {
mask = 0xff;
}
if (ch < 32) {
ch = 0xF0 | ( 15 - (ch/2) );
} else if (ch < 96) {
ch = 0xE0 | ( 15 - (ch-32)/4 );
} else if (ch < 224) {
ch = 0xD0 | ( 15 - (ch-96)/8 );
} else if (ch < 480) {
ch = 0xC0 | ( 15 - (ch-224)/16 );
} else if (ch < 992 ) {
ch = 0xB0 | ( 15 - (ch-480)/32 );
} else if (ch < 2016) {
ch = 0xA0 | ( 15 - (ch-992)/64 );
} else if (ch < 4064) {
ch = 0x90 | ( 15 - (ch-2016)/128 );
} else if (ch < 8160) {
ch = 0x80 | ( 15 - (ch-4064)/256 );
} else {
ch = 0x80;
}
return (uae_u8)(mask & ch);
}
void sample_ulaw_handler(void)
{
#ifndef DONT_WANT_SOUND
int nr;
uae_u32 data = 0;
eventtab[ev_sample].evtime += cycles - eventtab[ev_sample].oldcycles;
eventtab[ev_sample].oldcycles = cycles;
for (nr = 0; nr < 4; nr++) {
if (!(adkcon & (0x11 << nr)))
data += sound_table[audio_channel[nr].current_sample][audio_channel[nr].vol];
}
PUT_SOUND_BYTE (int2ulaw (data));
check_sound_buffers ();
#endif
}
#ifndef DONT_WANT_SOUND
static void audio_handler(int nr)
{
struct audio_channel_data *cdp = audio_channel + nr;
switch (cdp->state) {
case 0:
fprintf(stderr, "Bug in sound code\n");
break;
case 1:
/* We come here at the first hsync after DMA was turned on. */
eventtab[ev_aud0 + nr].evtime += maxhpos;
eventtab[ev_aud0 + nr].oldcycles += maxhpos;
cdp->state = 5;
INTREQ(0x8000 | (0x80 << nr));
if (cdp->wlen != 1)
cdp->wlen--;
cdp->nextdat = chipmem_bank.wget(cdp->pt);
cdp->pt += 2;
break;
case 5:
/* We come here at the second hsync after DMA was turned on. */
if (currprefs.produce_sound == 0)
cdp->per = 65535;
eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
eventtab[ev_aud0 + nr].oldcycles = cycles;
cdp->dat = cdp->nextdat;
cdp->current_sample = (uae_u8)(cdp->dat >> 8);
cdp->state = 2;
{
int audav = adkcon & (1 << nr);
int audap = adkcon & (16 << nr);
int napnav = (!audav && !audap) || audav;
if (napnav)
cdp->data_written = 2;
}
break;
case 2:
/* We come here when a 2->3 transition occurs */
if (currprefs.produce_sound == 0)
cdp->per = 65535;
cdp->current_sample = (uae_u8)(cdp->dat & 0xFF);
eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
eventtab[ev_aud0 + nr].oldcycles = cycles;
cdp->state = 3;
/* Period attachment? */
if (adkcon & (0x10 << nr)) {
if (cdp->intreq2 && cdp->dmaen)
INTREQ(0x8000 | (0x80 << nr));
cdp->intreq2 = 0;
cdp->dat = cdp->nextdat;
if (cdp->dmaen)
cdp->data_written = 2;
if (nr < 3) {
if (cdp->dat == 0)
(cdp+1)->per = 65535;
else if (cdp->dat < maxhpos/2 && currprefs.produce_sound < 3)
(cdp+1)->per = maxhpos/2;
else
(cdp+1)->per = cdp->dat;
}
}
break;
case 3:
/* We come here when a 3->2 transition occurs */
if (currprefs.produce_sound == 0)
cdp->per = 65535;
eventtab[ev_aud0 + nr].evtime = cycles + cdp->per;
eventtab[ev_aud0 + nr].oldcycles = cycles;
if ((INTREQR() & (0x80 << nr)) && !cdp->dmaen) {
cdp->state = 0;
cdp->current_sample = 0;
eventtab[ev_aud0 + nr].active = 0;
break;
} else {
int audav = adkcon & (1 << nr);
int audap = adkcon & (16 << nr);
int napnav = (!audav && !audap) || audav;
cdp->state = 2;
if ((cdp->intreq2 && cdp->dmaen && napnav)
|| (napnav && !cdp->dmaen))
INTREQ(0x8000 | (0x80 << nr));
cdp->intreq2 = 0;
cdp->dat = cdp->nextdat;
cdp->current_sample = (uae_u8)(cdp->dat >> 8);
if (cdp->dmaen && napnav)
cdp->data_written = 2;
/* Volume attachment? */
if (audav) {
if (nr < 3)
(cdp+1)->vol = cdp->dat;
}
}
break;
default:
cdp->state = 0;
eventtab[ev_aud0 + nr].active = 0;
break;
}
}
void aud0_handler(void)
{
audio_handler(0);
}
void aud1_handler(void)
{
audio_handler(1);
}
void aud2_handler(void)
{
audio_handler(2);
}
void aud3_handler(void)
{
audio_handler(3);
}
#endif